package cn.itsource.org.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import cn.itsource.common.domain.LoginData;
import cn.itsource.common.exception.BusinessException;
import cn.itsource.common.util.AjaxResult;
import cn.itsource.common.util.JwtUtils;
import cn.itsource.common.util.StrUtils;
import cn.itsource.org.domain.*;
import cn.itsource.org.dto.WxuserDto;
import cn.itsource.org.mapper.*;
import cn.itsource.org.ro.BindRo;
import cn.itsource.org.ro.LoginRo;
import cn.itsource.org.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Value("${wechat.appid}")
    private String appid;
    @Value("${wechat.secret}")
    private String secret;
    private String WECHAT_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
    private String USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";

    /**
     * 登录 功能
     * @param loginRo
     * @return
     */
    @Override
    public AjaxResult login(LoginRo loginRo) {
        String username = loginRo.getUsername();
        Logininfo logininfo =  logininfoMapper.findLoginInfoByKeyword(username);
        if(logininfo == null){
            throw new BusinessException("账号或者密码错误");
        }
        if(loginRo.getIsCheckPassword()){//默认是true
            String password = logininfo.getPassword();//加密后的密码
            String salt = logininfo.getSalt();//加密盐值
            String s = SecureUtil.md5(salt + loginRo.getPassword());//用户输入的密码加密
            if(!password.equals(s)){
                throw new BusinessException("账号或者密码错误");
            }
        }else {
            if(!logininfo.getPassword().equals(loginRo.getPassword())){
                throw new BusinessException("账号或者密码错误");
            }
        }
        LoginData loginData = new LoginData();
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        loginData.setLogininfo(logininfo);
        setMenuAndPermission(loginRo, logininfo, loginData);
        String token = JwtUtils.generateTokenExpireInSeconds(loginData,60*60*24);

        Map map = new HashMap(4);
        map.put("token",token);
        map.put("permission",loginData.getPermissions());
        map.put("menu",loginData.getMenus());
        map.put("user",loginData.getLogininfo());
        return AjaxResult.me().setResultObj(map);
        //-------------------------------------------------------------------
//        Map map = new HashMap(2);
//        String token = UUID.randomUUID().toString();
//        //存放redis
//        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
//        //在登录的时候要将对应的用户信息返回给前端
//        if (loginRo.getType() == 1){
//            User user = userMapper.findUserByLoginInfoId(logininfo.getId());
//            user.setPassword(null);
//            user.setSalt(null);
//            //查询用户
//            map.put("user",user);
//        }else {
//           Employee employee =  employeeMapper.findByLoginInfoId(logininfo.getId());
//            employee.setPassword(null);
//            employee.setSalt(null);
//            //查询管理员
//            map.put("user",employee);
//        }
//        map.put("token",token);
//        return AjaxResult.me().setResultObj(map);
    }

    private void setMenuAndPermission(LoginRo loginRo, Logininfo logininfo, LoginData loginData) {
        //只有后台用户需要权限和菜单  而 前台用户不需要权限和菜单
        if(loginRo.getType() == 0){//只有管理员需要
            Long id = logininfo.getId();//得到id去查询employee
            //得到当前登录人的所有菜单信息  但是没有上级目录
            List<Menu> menus = employeeMapper.getMenu(id);
            //取出所有的父id
            List<Long> menuPId = menus.stream().map(Menu::getParentId)
                    .distinct()
                    .collect(Collectors.toList());
            //查询父级目录
            List<Menu> menuList = menuMapper.findInIds(menuPId);
            menuList.addAll(menus);//进行和并  但是不是一棵树
            //将 查询出来的菜单变成一棵树
            List<Menu> menuTree = new ArrayList<>();
            Map<Long, Menu> collect = menuList.stream().distinct()
                    .collect(Collectors.toMap(Menu::getId, s -> s));
            menuList.stream().distinct().forEach(menu -> {
                if(menu.getParentId() == null){
                    menuTree.add(menu);
                }else {
                    Menu menu1 = collect.get(menu.getParentId());
                    menu1.getChildren().add(menu);
                }
            });
            //查询菜单
//            loginData.setMenus(menuTree);
            //查询权限
            List<Permission> permissions = employeeMapper.getPermissions(id);
            loginData.setPermissions(permissions);
        }
    }

    /**
     * 微信登录 通过code获取access_token
     * @param code
     * @return
     */
    @Override
    public AjaxResult wechat(String code) {
        String url = String.format(WECHAT_URL, appid, secret, code);
        //发送请求
        String result = HttpUtil.get(url);
        System.out.println(result);//json字符串
        JSONObject jsonObject = JSONObject.parseObject(result);
        Object access_token = jsonObject.get("access_token");
        System.out.println(access_token.toString());
        Object openid = jsonObject.get("openid");
        System.out.println(openid.toString());
        //去验证用户是不是第一次来
        Wxuser wxuser =  wxuserMapper.findWxUserByOpenid(openid.toString());
        if(wxuser == null){
            //逻辑 用 openid 去数据库里面查询  有第二次来  没有第一来
            getWechatInfo(access_token.toString(),openid.toString());
            return AjaxResult.me().setSuccess(false).setResultObj(openid);
        }
        if(wxuser.getUserId() == null){
            //你要去绑定
            return AjaxResult.me().setSuccess(false).setResultObj(openid);
        }
        //用户已经绑定成功  那么就直接去调用登录接口  登录就行
        Long userId = wxuser.getUserId();
        User user = userMapper.findById(userId);
        //调用登录接口 直接登录
        LoginRo loginRo = new LoginRo();
        loginRo.setType(1);
        loginRo.setUsername(user.getUsername());
        loginRo.setPassword(user.getPassword());
        loginRo.setIsCheckPassword(false);
        return login(loginRo);
    }

    @Override
    public AjaxResult bind(BindRo bindRo) {
        //第一种 当前这个账号 系统里面没有
        String username = bindRo.getUsername();
        User user = userMapper.findUserByPhone(username);
        if(user == null){
            //出注册 或者是抛出异常
            throw new BusinessException("当前账号不存在请先注册");
        }
        //第三种 当前这个账号 系统里面有 但是已经绑定了微信账号
        Wxuser wxuser = wxuserMapper.findWxUserByUserId(user.getId());
        if(wxuser == null){
            Wxuser wxUserByOpenid = wxuserMapper.findWxUserByOpenid(bindRo.getOpenId());
            wxUserByOpenid.setUserId(user.getId());
            wxuserMapper.update(wxUserByOpenid);
        }else {
            //第二种 当前这个账号 系统里面有
            //出注册 或者是抛出异常
            throw new BusinessException("当前账号已经被绑定过");
        }
        //调用登录接口 直接登录
        LoginRo loginRo = new LoginRo();
        loginRo.setType(1);
        loginRo.setUsername(user.getUsername());
        loginRo.setPassword(user.getPassword());
        loginRo.setIsCheckPassword(false);
        return login(loginRo);
    }

    /**
     * 去微信获取用户信息进行保存数据库
     * @param accessToken
     * @param openid
     */
    public void getWechatInfo(String accessToken,String openid){
        String url = String.format(USER_INFO_URL, accessToken, openid);
        String result = HttpUtil.get(url);
        WxuserDto wxuserDto = JSONObject.parseObject(result, WxuserDto.class);
        Wxuser wxuser = WxuserDto.WxuserDtoToWxuser(wxuserDto);
        wxuserMapper.save(wxuser);
    }
}
